package br.ufrj.dcc.ad.model;

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import br.ufrj.dcc.ad.ADSimProperties;
import br.ufrj.dcc.ad.Simulator;
import br.ufrj.dcc.ad.Util;
import br.ufrj.dcc.ad.event.AckReceivedEvent;

public class RxTCP {
	
	Logger logger = LoggerFactory.getLogger(RxTCP.class);
	
	private final Integer sessionId;
	
	TreeSet<Long> receiveds = new TreeSet<Long>();
	
	public RxTCP(Integer sessionId) {
		this.sessionId = sessionId;
		receiveds.add(-1500l);
	}
	
	public ACK receivePackage(Package pack) {
		if (pack.getSessionId().intValue() != this.sessionId.intValue()) {
			throw new IllegalStateException("RxTCP recebendo pacote indevido.");
		}
		
		final Long receivedNow = pack.getLeftByte();
		
		logger.info("{} recebido pelo receptor", pack.toString());
		
		if (receivedNow.compareTo(receiveds.first()) > 0) {
			receiveds.add(receivedNow);
		}
		
		final Iterator<Long> iterator = receiveds.iterator();
		final Set<Long> toRemove = new HashSet<Long>();
		Long item1 = iterator.next();
		while (iterator.hasNext()) {
			Long item2 = iterator.next();
			if (ADSimProperties.getMSS().compareTo(item2-item1) == 0) {
				toRemove.add(item1);
			} else {
				break;
			}
			item1 = item2;
		}
		receiveds.removeAll(toRemove);
		
		final Long nextByte = receiveds.first() + ADSimProperties.getMSS(); 
		final ACK ack = new ACK(this.sessionId, nextByte, pack);
		final double waitTime = pack.getPropagationTime();
		final AckReceivedEvent ackReceivedEvent = new AckReceivedEvent(waitTime, ack);
		Simulator.addEvent(ackReceivedEvent);
		
		return ack;
	}

}
